--'------------------------------------------------------------------------------------------------------------------- --' Схема озвучки --' автор: Диденко Руслан (Stohe) --'-------------------------------------------------------------------------------------------------------------------- --function printf() --end sound_table = {} function set_sound_play(npc_id, sound, faction, point) if not (sound and sound_theme.theme[sound]) then callstack() printf("set_sound_play. Wrong sound theme [%s], npc[%s]", tostring(sound), npc_id) return end local snd_theme = sound_theme.theme[sound] if snd_theme.class_id == "looped_sound" then printf("You trying to play sound [%s] which type is looped", sound) end if sound_table[npc_id] == nil or snd_theme.play_always == true then if (sound_table[npc_id] and sound_table[npc_id].reset) then sound_table[npc_id]:reset(npc_id) end if snd_theme:play(npc_id, faction, point,sound) then sound_table[npc_id] = snd_theme end end return sound_table[npc_id] and sound_table[npc_id].snd_obj end function update(npc_id) if not sound_table[npc_id] then return end if not(sound_table[npc_id]:is_playing(npc_id)) then sound_table[npc_id]:callback(npc_id) sound_table[npc_id] = nil end end looped_sound = {} function play_sound_looped(npc_id, sound) --utils_data.debug_write(strformat("xr_sound:play_sound_looped %s",sound)) local snd_theme = sound_theme.theme[sound] if snd_theme == nil then printe("!ERROR: play_sound_looped. Wrong sound theme [%s], npc[%s]", tostring(sound), npc_id) return end if snd_theme.class_id ~= "looped_sound" then printe("!ERROR: You trying to play sound [%s] which type is not looped", sound) return end if looped_sound[npc_id] ~= nil and looped_sound[npc_id][sound] ~= nil and looped_sound[npc_id][sound]:is_playing(npc_id) then return end if snd_theme:play(npc_id) then --printf("PLAY2. looped theme[%s] object[%s]", tostring(sound), npc_id) if looped_sound[npc_id] == nil then looped_sound[npc_id] = {} end looped_sound[npc_id][sound] = snd_theme end end function stop_sound_looped(npc_id, sound) if not (looped_sound[npc_id]) then return end if sound then if type(looped_sound[npc_id][sound]) ~= "string" then if looped_sound[npc_id][sound] and looped_sound[npc_id][sound]:is_playing(npc_id) then --printf("looped sound ["..tostring(sound).."] stop for obj [%s]",npc_id) looped_sound[npc_id][sound]:stop() looped_sound[npc_id][sound] = nil end end else for k,v in pairs(looped_sound[npc_id]) do if v and type(v) ~= "string" and v:is_playing(npc_id) then --printf("looped sound ["..tostring(k).."] stop for obj [%s]",npc_id) v:stop() end end looped_sound[npc_id] = nil end end function set_volume_sound_looped(npc_id, sound, level) if looped_sound[npc_id] then if looped_sound[npc_id][sound] and looped_sound[npc_id][sound]:is_playing(npc_id) then --printf("looped sound ["..tostring(sound).."] for obj ["..npc_id.."] set volume "..level) looped_sound[npc_id][sound]:set_volume(level) end end end function actor_save_state(m_data) --utils_data.debug_write("actor_save_state") m_data.xr_sound = empty_table(m_data.xr_sound) for k,v in pairs(sound_theme.theme) do v:save_state(m_data.xr_sound) end m_data.xr_sound.sound_table = {} for k,v in pairs(sound_table) do m_data.xr_sound.sound_table[k] = v.section end m_data.xr_sound.looped_sound = {} for k,v in pairs(looped_sound) do m_data.xr_sound.looped_sound[k] = {} for kk,vv in pairs(looped_sound[k]) do m_data.xr_sound.looped_sound[k][kk] = true end end end function actor_load_state(m_data) if not (m_data.xr_sound) then return end for k,v in pairs(sound_theme.theme) do v:load_state(m_data.xr_sound) end for k,v in pairs(m_data.xr_sound.sound_table) do if (sound_theme.theme[v]) then sound_table[k] = sound_theme.theme[v] end end for k,v in pairs(m_data.xr_sound.looped_sound) do looped_sound[k] = {} for kk,vv in pairs(m_data.xr_sound.looped_sound[k]) do if (sound_theme.theme[kk]) then looped_sound[k][kk] = sound_theme.theme[kk] end end end m_data.xr_sound = nil end function actor_save(stpk) set_save_marker(stpk, "save", false, "sound_actor_save") for k,v in pairs(sound_theme.theme) do v:save(stpk) end local n = 0 for k,v in pairs(sound_table) do n = n + 1 end utils_data.w_stpk(stpk,"u16",n,"sound table count") for k,v in pairs(sound_table) do utils_data.w_stpk(stpk,"u16",k,"sound table:sound_id") utils_data.w_stpk(stpk,"stringZ",v.section,"sound table:sound section") end n = 0 for k,v in pairs(looped_sound) do n = n + 1 end utils_data.w_stpk(stpk,"u16",n,"looped sound count") for k,v in pairs(looped_sound) do utils_data.w_stpk(stpk,"u16",k,"sound table:looped sound_id") n = 0 for kk,vv in pairs(looped_sound[k]) do n = n + 1 end utils_data.w_stpk(stpk,"u16",n,"sound table:looped "..n) for kk,vv in pairs(looped_sound[k]) do utils_data.w_stpk(stpk,"stringZ",kk,"sound table:looped "..n.." section") end end set_save_marker(stpk, "save", true, "sound_actor_save") end function actor_load(stpk) set_save_marker(stpk, "load", false, "sound_actor_save") for k,v in pairs(sound_theme.theme) do v:load(stpk) end sound_table = {} local n = stpk:r_u16() for i = 1,n do local id = stpk:r_u16() local theme = stpk:r_stringZ() -- sound_table[id] = stpk:r_stringZ() sound_table[id] = sound_theme.theme[theme] end looped_sound = {} n = stpk:r_u16() for i = 1,n do local id = stpk:r_u16() looped_sound[id] = {} n = stpk:r_u16() for i = 1,n do local sound = stpk:r_stringZ() -- looped_sound[id][sound] = stpk:r_stringZ() looped_sound[id][sound] = sound_theme.theme[sound] end end set_save_marker(stpk, "load", true, "sound_actor_save") end function npc_save_state(id,m_data) --utils_data.debug_write("npc_save_state") m_data.xr_sound = empty_table(m_data.xr_sound) for k,v in pairs(sound_theme.theme) do v:save_state(m_data.xr_sound) end end function npc_load_state(id,m_data) if not (m_data.xr_sound) then return end for k,v in pairs(sound_theme.theme) do v:load_state(m_data.xr_sound) end m_data.xr_sound = nil end function save_npc(stpk, npc_id) --utils_data.debug_write("xr_sound:save_npc") set_save_marker(stpk, "save", false, "sound_npc_save") for k,v in pairs(sound_theme.theme) do v:save_npc(stpk, npc_id) end set_save_marker(stpk, "save", true, "sound_npc_save") end function load_npc(stpk, npc_id) --utils_data.debug_write("xr_sound:load_npc") set_save_marker(stpk, "load", false, "sound_npc_save") for k,v in pairs(sound_theme.theme) do v:load_npc(stpk, npc_id) end set_save_marker(stpk, "load", true, "sound_npc_save") end function stop_all_sounds() for k,v in pairs(sound_table) do if(type(v)~="string") then v:stop() end end for k,v in pairs(looped_sound) do for k,v in pairs(looped_sound[k]) do if v and v:is_playing(npc_id) then printf("looped sound ["..tostring(k).."] stopped ") v:stop() end end end end function stop_sounds_by_id(obj_id) local sound = sound_table[obj_id] if sound and sound.stop then sound:stop(obj_id) end local looped_snd = looped_sound[obj_id] if looped_snd then for k,v in pairs(looped_snd) do if v and v:is_playing(obj_id) then v:stop(obj_id) end end end end --------------------------------------------------------------------------------------------------------------------- -- Схема озвучки -- автор: Диденко Руслан (Stohe) -- update: Чугай Александр (Chugai) ---------------------------------------------------------------------------------------------------------------------- key_by_id = {} group_idle = {} --function printf() --end function get_sound(path, tt, npc) if path == nil then return nil end if path.exec == nil then -- чтение настроек темы tt.into_id = path.into_id tt.into_max = path.max_ids[npc:id()].into_max tt.into_last = nil tt.rnd_id = path.rnd_id tt.rnd_max = path.max_ids[npc:id()].rnd_max tt.rnd_last = nil tt.min_snd = path.min_snd tt.max_snd = path.max_snd tt.rnd_snd = path.rnd_snd else get_sound(path.types[path.exec(path.types, npc)], tt, npc) end end -- Формирование ключа персонажа function get_key(npc) local key -- формирование ключа local overrides = xr_logic.generic_scheme_overrides(npc) if overrides and overrides.soundgroup then key = overrides.soundgroup else key = utils_data.to_str(npc:id()) end -- апдейт таблиц :) не менять! if xr_sound.key_by_id[npc:id()] ~= key then if xr_sound.group_idle[xr_sound.key_by_id[npc:id()]] ~= nil then xr_sound.group_idle[xr_sound.key_by_id[npc:id()]].num_in_group = xr_sound.group_idle[xr_sound.key_by_id[npc:id()]].num_in_group - 1 end xr_sound.key_by_id[npc:id()] = key if xr_sound.group_idle[key] == nil then xr_sound.group_idle[key] = {num_in_group = 1} else xr_sound.group_idle[key].num_in_group = xr_sound.group_idle[key].num_in_group + 1 end end return key end ----------------------------------------------------------------------------------------------------------------------------------- -- Установка и распарсивание тем в файлы. ----------------------------------------------------------------------------------------------------------------------------------- function set_sound(npc, sound, now, into_timeout) -- printf("*SND* [%s] try to change SND to [%s]", npc:name(), tostring(sound)) local npc_id = npc:id() if (db.sound[npc_id] == nil or db.sound[npc_id].theme ~= sound) or now == true then -- if db.sound[npc_id] == nil then -- printf("*SND* change SND [_] to [%s] for [%s]", tostring(sound), npc:name()) -- else -- printf("*SND* change SND [%s] to [%s] for [%s]", tostring(db.sound[npc_id].theme), tostring(sound), npc:name()) -- end -- Туточки надобно распарсить имена тем в их id if sound == nil then sound = "" end if db.sound[npc_id] == nil then db.sound[npc_id] = {} end db.sound[npc_id].theme = sound db.sound[npc_id].snd = parse_names(sound) if db.sound[npc_id].last_snd == nil then db.sound[npc_id].last_snd = {} else local snd_table = {} local t = 0 for k,v in pairs(db.sound[npc_id].snd) do snd_table[t] = {} get_sound(sound_theme.theme[v], snd_table[t], npc) t = t + 1 end for k,v in pairs(snd_table) do if v.into_id then db.sound[npc_id].last_snd[v.into_id] = nil end if v.rnd_id then db.sound[npc_id].last_snd[v.rnd_id] = nil end end end -- Устанавливаем входную паузу local key = get_key(npc) xr_sound.group_idle[key].begin = time_global() if into_timeout then xr_sound.group_idle[key].idle = into_timeout else xr_sound.group_idle[key].idle = 0 end if now == true then stop_play_sound(npc) end end end function play_sound(npc, themes, timeout) --utils_data.debug_write(strformat("xr_sound:play_sound %s",npc and npc:name())) -- нужно составить список тем local snd_table = {} local t = 0 for k,v in pairs(themes) do snd_table[t] = {} if sound_theme.theme[v] ~= nil then snd_table[t].theme = v get_sound(sound_theme.theme[v], snd_table[t], npc) else printe("!ERROR: ILLEGAL PLAY SOUND!!! %s for %s", v, npc:name()) end t = t + 1 end --printf("*") --print_table(snd_table) if t == 0 then return end -- из списка тем выбираем одну. local snd = snd_table[math.random(0, t-1)] if snd ~= nil then --printf("!") --print_table(snd) if snd.min_snd == nil then return end local npc_id = npc:id() local group_table = xr_sound.group_idle[get_key(npc)] group_table.idle = math.random(snd.min_snd, snd.max_snd)*1000 if group_table.last_snd == nil then group_table.last_snd = {} end -- необходимо ли нам играть into или rnd звуки if snd.into_max ~= nil and snd.into_max > 0 then if db.sound[npc_id].last_snd[snd.into_id] == snd.into_max - 1 then if snd.into_cycled == true then db.sound[npc_id].last_snd[snd.into_id] = nil else return end end -- играем входные if db.sound[npc_id].last_snd[snd.into_id] == nil then db.sound[npc_id].last_snd[snd.into_id] = -1 end --printf("*SND* play seq [%s] for [%s]", db.sound[npc_id].last_snd[snd.into_id]+1, npc:name()) process_tutor_on_sound(snd.theme) npc:play_sound(snd.into_id, 1, 0, 1, 0, db.sound[npc_id].last_snd[snd.into_id]+1) db.sound[npc_id].last_snd[snd.into_id] = db.sound[npc_id].last_snd[snd.into_id] + 1 --printf("*SND* play seq [%s] for [%s]", db.sound[npc_id].last_snd[snd.into_id], npc:name()) return end if snd.rnd_max ~= nil and snd.rnd_max > 0 then -- играем рандомные local s = 0 if snd.rnd_max == 1 then s = 0 else -- Если прошлый раз проигрывался такой же набор тем -- то учитывать последний звук для группы. -- if db.sound[npc_id].last_snd[snd.rnd_id] ~= nil then if group_table.last_snd[snd.rnd_id] ~= nil then s = math.random(0, snd.rnd_max-2) if s >= group_table.last_snd[snd.rnd_id] then s = s + 1 end else s = math.random(0, snd.rnd_max-1) end end if timeout == nil then timeout = 0 end --printf("*SND* play rnd [%s] for [%s]", s, npc:name()) process_tutor_on_sound(snd.theme) npc:play_sound(snd.rnd_id, timeout+1, timeout, 1, 0, s) --db.sound[npc_id].last_snd[snd.rnd_id] = s group_table.last_snd[snd.rnd_id] = s end end end function get_last_IDS(npc, theme) local last_table = db.sound[npc:id()].last_snd local snd_table = {} if sound_theme.theme[theme] ~= nil then get_sound(sound_theme.theme[theme], snd_table, npc) end --printf("LAST INTO ID for [%s] = [%s], max [%s]", theme, last_table[snd_table.into_id], snd_table.into_max) return last_table[snd_table.into_id], snd_table.into_max end function process_tutor_on_sound(theme) end --' Actor sound player local actor_sound = {} function set_actor_sound(sound) --printf("*ACTOR SND* try to change SND to [%s]", tostring(sound)) if actor_sound.theme ~= sound then --' Туточки надобно распарсить имена тем в их id if sound == nil then sound = "" end actor_sound.theme = sound actor_sound.begin = nil this.set_actor_sound_factor(1) end end function set_actor_sound_factor(factor) local theme = sound_theme.actor_theme[actor_sound.theme] if theme ~= nil then actor_sound.min_snd = theme.min_snd * factor actor_sound.max_snd = theme.max_snd * factor end end function update_actor() local theme = sound_theme.actor_theme[actor_sound.theme] if theme == nil then return end if table.getn(theme.sounds) == 0 then return end if actor_sound.begin == nil or time_global() - actor_sound.begin >= actor_sound.idle then actor_sound.begin = time_global() --' Тут надо отыграть звук local sound = theme.sounds[math.random(table.getn(theme.sounds))] if sound ~= nil then sound:play(db.actor, 0, sound_object.s2d) end actor_sound.idle = math.random(actor_sound.min_snd, actor_sound.max_snd) end end -- modified by Alundaio (original: ????) --' Таблица для хранения созданных саунд обжектов. --' type = [random|seq|looped] local ltx = ini_file("plugins\\xr_sound.ltx") function get_sound_object(theme, t_type) if not (ph_snd_themes) then ph_snd_themes = {} ph_snd_themes[theme] = utils_data.collect_section(ltx,theme) --printf("collect theme=%s",theme) end if (not ph_snd_themes or not ph_snd_themes[theme]) then --printf("no ph_snd_themes theme=%s",theme) return end if not (sound_object_by_theme) then sound_object_by_theme = {} end if (not sound_object_by_theme[theme])then sound_object_by_theme[theme] = {} end if t_type == nil then t_type = "random" end --' Выбор следующего айдишника local play_id = -1 local table_size = #ph_snd_themes[theme] if (table_size == 0) then return end --printf("tablesize = %s theme=%s",table_size,theme) if sound_object_by_theme[theme].last_id == nil then if t_type == "random" then if table_size >= 2 then play_id = math.random(1, table_size) else play_id = 1 end else play_id = 1 end else if t_type == "random" then if table_size >= 2 then play_id = math.random(1, table_size - 1) if play_id >= sound_object_by_theme[theme].last_id then play_id = play_id + 1 end else play_id = 1 end else if sound_object_by_theme[theme].last_id < table_size then play_id = sound_object_by_theme[theme].last_id + 1 else if type == "looped" then play_id = 1 end end end end --printf("SOUND_OBJECT: selected id [%s] for theme [%s], type [%s], size [%s]", tostring(play_id), tostring(theme), tostring(type), table_size) if play_id == -1 then return end --' Проверяем создан ли у нас соответствующий саунд обжект или его надо создать if sound_object_by_theme[theme][play_id] == nil then if type(ph_snd_themes[theme][play_id]) == "table" then sound_object_by_theme[theme][play_id.."_r"] = get_safe_sound_object(ph_snd_themes[theme][play_id][1].."_r") sound_object_by_theme[theme][play_id.."_l"] = get_safe_sound_object(ph_snd_themes[theme][play_id][1].."_l") else sound_object_by_theme[theme][play_id] = get_safe_sound_object(ph_snd_themes[theme][play_id]) end end sound_object_by_theme[theme].last_id = play_id --' Возвращаем саунд обжект if type(ph_snd_themes[theme][play_id]) == "table" then return sound_object_by_theme[theme][play_id.."_r"], sound_object_by_theme[theme][play_id.."_l"] else return sound_object_by_theme[theme][play_id] end end local sound_object_by_path = {} --' Обертка вокруг функции, возвращающий звуковой объект. function get_safe_sound_object(path) if sound_object_by_path[path] == nil then sound_object_by_path[path] = sound_object(path) end return sound_object_by_path[path] end function stop_all_sound_object() for k,v in pairs(sound_object_by_path) do if v:playing() then v:stop() end end end function clear_all_sound_object() sound_object_by_theme = {} end